#pragma once
#include <iostream>
#include <algorithm>
#include <mutex>
#include <vector>
#include <unordered_map>
#include <cstdlib>
#include <ctime>
#include <string>
#include <cassert>
#include <thread>

using std::endl, std::cout, std::cin;
using std::vector, std::string, std::unordered_map;

static const int MAX_BYTES = 1024 * 256;
static const int NFREE_LIST = 208;
static const int NPAGES = 129;
static const int PAGE_SHIFT = 13;
#ifdef _WIN32
#include <windows.h> // Windows下VirtualAlloc所需头文件
using PAGE_ID = size_t;
#elif defined(_WIN32) && defined(_WIN64)
#include <windows.h> // Windows下VirtualAlloc所需头文件
using PAGE_ID = unsigned long long;
#elif defined(__linux__)
// Ubuntu/Linux环境（__linux__是Linux系统的预定义宏）
#if defined(__x86_64__) || defined(__aarch64__)
// Linux 64位架构（x86_64或ARM64，Ubuntu常见架构）
using PAGE_ID = unsigned long long;

#include <cstddef>
#include <sys/mman.h> // Linux下mmap所需头文件
#include <unistd.h>   // 包含brk等函数声明（如需使用）
#else
// Linux 32位架构（如x86）
using PAGE_ID = size_t;
#endif
#endif
inline static void *SystemAlloc(size_t kpage)
{

#ifdef _WIN32
    // Windows平台使用VirtualAlloc
    // 注意：原代码缺少分号，已补充
    void *ptr = VirtualAlloc(
        nullptr,                  // 让系统自动选择分配地址
        kpage << 13,                     // 分配大小（字节）
        MEM_COMMIT | MEM_RESERVE, // 同时提交并保留内存
        PAGE_READWRITE            // 读写权限
    );
#else
    // Linux平台使用mmap（匿名映射，适合内存池场景）
    void *ptr = mmap(
        nullptr,                     // 让系统自动选择映射地址
        kpage << 13,                        // 映射大小（字节）
        PROT_READ | PROT_WRITE,      // 读写权限
        MAP_PRIVATE | MAP_ANONYMOUS, // 私有匿名映射（不关联文件）
        -1,                          // 匿名映射无需文件描述符
        0                            // 偏移量（匿名映射必须为0）
    );

    // mmap失败时返回MAP_FAILED，需要转换为nullptr
    if (ptr == MAP_FAILED)
    {
        ptr = nullptr;
    }
#endif

    return ptr;
}
static void *&NextObj(void *obj)
{
    return *(void **)obj;
}
// 管理切分好的小对象的自由链表
class FreeList
{
public:
    void Push(void *obj)
    {
        // 头插
        assert(obj);
        NextObj(obj) = _freeList;
        _freeList = obj;

        ++_size;
    }

    void PushRange(void *start, void *end, size_t n)
    {
        NextObj(end) = _freeList;
        _freeList = start;
        _size += n;
    }
    void *Pop()
    {
        // 头删
        void *obj = _freeList;
        _freeList = NextObj(_freeList);
        return obj;
        --_size;
    }
    bool Empty()
    {
        return _freeList == nullptr;
    }
    size_t &MaxSize()
    {
        return _maxSize;
    }
    void PopRange(void*& start, void*& end, size_t n)
    {
        assert(n >= _size);
        _size -= n;
        start = _freeList;
        end = start;
        for (size_t i = 0; i < n - 1; i++)
        {
            end = NextObj(end);
        }
        _freeList = NextObj(end);
        NextObj(end) = nullptr;
    }

    size_t Size()
    {
        return _size;
    }
private:
    void *_freeList = nullptr;
    size_t _maxSize = 1;
    size_t _size = 0;
};

// 计算对象大小对其的类

class SizeClass
{
public:
    // 整体控制在最多10%左右的内碎⽚浪费
    // [1,128] 8byte对⻬ freelist[0,16)
    // [128+1,1024] 16byte对⻬ freelist[16,72)
    // [1024+1,81024] 128byte对⻬ freelist[72,128)
    // [8*1024+1,641024] 1024byte对⻬ freelist[128,184)
    // [64*1024+1,256*1024] 8*1024byte对⻬ freelist[184,208)
    // zdl:: 这样的方式会存在相应的浪费，但还是在一个可接受的范围
    // size_t _RoundUp(size_t size, size_t alignNum)
    // {
    //     size_t alignSize;
    //     if (size % 8)
    //     {
    //         alignSize = (size / alignSize + 1) * alignNum;
    //     }
    //     else
    //     {
    //         alignSize = size;
    //     }

    //     return alignSize;
    // }
    // 高级写法！
    static inline size_t _RoundUp(size_t bytes, size_t alignNum)
    {
        return ((bytes + alignNum - 1) & ~(alignNum - 1));
    }
    static inline size_t RoundUp(size_t size)
    {
        if (size <= 128)
        {
            return _RoundUp(size, 8);
        }
        else if (size <= 1024)
        {

            return _RoundUp(size, 16);
        }
        else if (size <= 8 * 1024)
        {

            return _RoundUp(size, 128);
        }
        else if (64 * 1024)
        {

            return _RoundUp(size, 1024);
        }
        else if (size <= 256 * 1024)
        {

            return _RoundUp(size, 8 * 1024);
        }
        else
        {
            assert(false);
            return -1;
        }
    }
    static inline size_t _Index(size_t bytes, size_t align_shift)
    {
        return ((bytes + (1 << align_shift) - 1) >> align_shift) - 1;
    }

    // 计算映射的哪⼀个⾃由链表桶
    static inline size_t Index(size_t bytes)
    {
        assert(bytes <= MAX_BYTES);
        // 每个区间有多少个链
        static int group_array[4] = {16, 56, 56, 56};
        if (bytes <= 128)
        {
            return _Index(bytes, 3);
        }
        else if (bytes <= 1024)
        {
            return _Index(bytes - 128, 4) + group_array[0];
        }
        else if (bytes <= 81024)
        {
            return _Index(bytes - 1024, 7) + group_array[1] + group_array[0];
        }
        else if (bytes <= 64 * 1024)
        {
            return _Index(bytes - 8 * 1024, 10) + group_array[2] +
                   group_array[1] + group_array[0];
        }
        else if (bytes <= 256 * 1024)
        {
            return _Index(bytes - 64 * 1024, 13) + group_array[3] +
                   group_array[2] + group_array[1] + group_array[0];
        }
        else
        {
            assert(false);
        }
        return -1;
    }
    // ⼀次从中⼼缓存获取多少个
    static size_t NumMoveSize(size_t size)
    {
        assert(size > 0);
        // [2, 512]，⼀次批量移动多少个对象的(慢启动)上限值
        // ⼩对象⼀次批量上限⾼
        // ⼩对象⼀次批量上限低
        int num = MAX_BYTES / size;
        if (num < 2)
            num = 2;
        if (num > 512)
            num = 512;
        return num;
    }
    static size_t NumMovePage(size_t size)
    {
        size_t num = NumMoveSize(size);
        size_t npage = num * size;
        npage >>= PAGE_SHIFT;
        if (npage == 0)
            npage = 1;
        return npage;
    }

private:
};

// zdl:: 管理多个连续页的大块内存跨度结构
struct Span
{
    PAGE_ID _pageId; // 大块内存的其实页号
    size_t _n;       // 页的数量

    Span *_next = nullptr; // 双向列表的结构
    Span *_prev = nullptr;

    size_t _useCount;          // 切好的小块内存， 被分配给 thread Cache的计数
    void *_freeList = nullptr; // 切好的小块内存自由链表
};

// 带头双向列表
class SpanList
{
public:
    SpanList()
    {
        _head = new Span();
        _head->_next = _head;
        _head->_prev = _head;
    }
    void Insert(Span *pos, Span *newSpan)
    {
        assert(pos && newSpan);
        newSpan->_next = pos->_next;
        newSpan->_prev = pos;
        pos->_next = newSpan;
    }
    void Erase(Span *pos)
    {
        assert(pos && pos != _head);
        auto prev = pos->_prev, next = pos->_next;
        prev->_next = next;
        next->_prev = prev;
        // 在这立我们并不是要将这个空间释放掉，而是要将其归还给 centralCache
        // delete pos;
    }
    Span *Begin()
    {
        return _head->_next;
    }
    Span *End()
    {
        return _head;
    }
    void PushFront(Span *span)
    {
        Insert(Begin(), span);
    }
    Span *PopFront()
    {
        auto front = _head->_next;
        Erase(front);
        return front;
    }
    bool Empty()
    {
        return _head->_next == _head;
    }
    std::mutex _mtx; // 桶锁

private:
    Span *_head;
};
